﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace Libium.Controls
{
	public partial class ManualFlowLayoutControl : UserControl
	{

		public List<Control> items = new List<Control>();
		Size prevSize = new Size(0, 0);
		FlowDirection _FlowDirection = FlowDirection.LeftToRight;

		public ManualFlowLayoutControl()
		{
			InitializeComponent();
			prevSize = new Size(this.Width, this.Height);
		}

		private void ManualFlowLayoutControl_ControlAdded(object sender, ControlEventArgs e)
		{
			if (e.Control == null)
				return;
			items.Add(e.Control);
			ReorderItems();
			this.Invalidate();
		}

		private void ManualFlowLayoutControl_ControlRemoved(object sender, ControlEventArgs e)
		{
			if (e.Control == null)
				return;
			items.Remove(e.Control);
			ReorderItems();
			this.Invalidate();
		}

		private void ManualFlowLayoutControl_Resize(object sender, EventArgs e)
		{
			if (!prevSize.Equals(this.Size))
			{
				ReorderItems();
				this.Invalidate();
				prevSize = new Size(this.Width, this.Height);
			}
		}

		private void ManualFlowLayoutControl_SizeChanged(object sender, EventArgs e)
		{
			if (!prevSize.Equals(this.Size))
			{
				ReorderItems();
				this.Invalidate();
				prevSize = new Size(this.Width, this.Height);
			}
		}

		public FlowDirection FlowDirection
		{
			get
			{
				return _FlowDirection;
			}
			set
			{
				if (_FlowDirection != value)
				{
					_FlowDirection = value;
					ReorderItems();
					this.Invalidate();
				}
			}
		}

		private void ReorderItems()
		{
			switch (_FlowDirection)
			{
				#region #FlowDirection.LeftToRight
				case System.Windows.Forms.FlowDirection.LeftToRight:
					{
						int requiredTotalheight = 0;
						int requiredMinWidth = 0;

						int curLineY = 0;

						int dw = 0;
						int dh = 0;
						int prevDh = 0;
						foreach (Control c in items)
						{
							prevDh = dh;
							if (c.Margin.Top + c.Margin.Bottom + c.Height > dh)
								dh = c.Margin.Top + c.Margin.Bottom + c.Height;

							if (dw + c.Width + c.Margin.Left + c.Margin.Right >= this.Width)
							{
								if (dw == 0)
								{
									// at least one control should be added to this row, even if it does not fit                              
									c.Location = new Point(c.Margin.Left, curLineY + c.Margin.Top);

									// size needed for this row to be drawn in it's entirety (for the longest 1-column layout)
									if (requiredMinWidth < c.Width + c.Margin.Left + c.Margin.Right)
										requiredMinWidth = c.Width + c.Margin.Left + c.Margin.Right;
									// next line starts
									curLineY += dh;
									dh = 0;
									dw = 0;
								}
								else
								{
									// this control goes to next line
									// next line starts
									curLineY += prevDh;
									if (prevDh == 0)
										curLineY += dh;
									prevDh = 0;
									dh = 0;
									dw = c.Width + c.Margin.Left + c.Margin.Right;
									c.Location = new Point(c.Margin.Left, curLineY + c.Margin.Top);
									if (requiredMinWidth < c.Width + c.Margin.Left + c.Margin.Right)
										requiredMinWidth = c.Width + c.Margin.Left + c.Margin.Right;
								}
							}
							else
							{
								// add this control to the current line too
								c.Location = new Point(dw + c.Margin.Left, curLineY + c.Margin.Top);
								dw += c.Width + c.Margin.Left + c.Margin.Right;
								if (requiredMinWidth < dw)
									requiredMinWidth = dw;
							}

							requiredTotalheight = curLineY + dh;
							if (dh == 0)
							{
								requiredTotalheight += c.Margin.Top + c.Margin.Bottom + c.Height;
							}
						}

						this.SuspendLayout();
						this.Height = requiredTotalheight;
						if (requiredMinWidth > this.Width)
						{
							this.Width = requiredMinWidth;
						}
						this.ResumeLayout(true);
					}
					break;
				#endregion
				#region #FlowDirection.BottomUp
				case System.Windows.Forms.FlowDirection.BottomUp:
					{
					}
					break;
				#endregion
				#region #FlowDirection.RightToLeft
				case System.Windows.Forms.FlowDirection.RightToLeft:
					{
					}
					break;
				#endregion
				#region #FlowDirection.TopDown
				case System.Windows.Forms.FlowDirection.TopDown:
					{
					}
					break;
				#endregion
			}
		}

		public void EnsureOrder()
		{
			ReorderItems();
			Refresh();
		}

	}
}
